package edu.kufpg.armatus.console;
import java.util.List;
import java.util.Locale;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import edu.kufpg.armatus.R;
import edu.kufpg.armatus.data.CommandInfo;
/**
* {@link android.widget.ExpandableListAdapter ExpandableListAdapter} for a menu containing
* {@link DragIcon}s representing various console {@link
* edu.kufpg.armatus.console.CustomCommandInfo.CommandInfo Command}s.
*/
public class CommandExpandableMenuAdapter extends BaseExpandableListAdapter implements Filterable {
private final LayoutInflater mInflater;
private Filter mFilter;
private CharSequence mConstraint;
private final Object mLock = new Object();
private List<String> mTags;
private ListMultimap<String, String> mTagCommandNames;
/**
* Constructs a new instance and initializes the menu data if necessary.
* @param context The {@link Context} to use.
*/
public CommandExpandableMenuAdapter(Context context) {
mInflater = LayoutInflater.from(context);
resetData();
}
public CommandExpandableMenuAdapter(Context context, CharSequence searchConstraint) {
this(context);
getFilter().filter(searchConstraint);
}
@Override
public String getChild(int groupPosition, int childPosition) {
return mTagCommandNames.get(getGroup(groupPosition)).get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View view, ViewGroup parent) {
CommandExpandableMenuItem item;
if (view == null) {
view = mInflater.inflate(R.layout.command_expandable_child, null);
item = new CommandExpandableMenuItem();
item.commandName = (TextView) view.findViewById(R.id.command_expandable_command_name);
item.typeSigs = (TextView) view.findViewById(R.id.command_expandable_type_sigs);
view.setTag(item);
} else {
item = (CommandExpandableMenuItem) view.getTag();
}
String commandName = getChild(groupPosition, childPosition);
int typeSigs = CommandHolder.getCommandTypeSigCount(commandName);
item.commandName.setText(commandName);
item.commandName.setTypeface(ConsoleActivity.TYPEFACE);
item.typeSigs.setText(String.valueOf(typeSigs));
return view;
}
@Override
public int getChildrenCount(int groupPosition) {
return mTagCommandNames.get(getGroup(groupPosition)).size();
}
@Override
public String getGroup(int groupPosition) {
return mTags.get(groupPosition);
}
@Override
public int getGroupCount() {
return mTags.size();
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isLastChild, View view, ViewGroup parent) {
String tagName = getGroup(groupPosition);
CommandExpandableMenuHeader header;
if (view == null) {
view = mInflater.inflate(R.layout.command_expandable_group, null);
header = new CommandExpandableMenuHeader();
header.title = (TextView) view.findViewById(R.id.group_heading);
view.setTag(header);
} else {
header = (CommandExpandableMenuHeader) view.getTag();
}
header.title.setText(tagName);
return view;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
@Override
public void notifyDataSetChanged() {
if (mConstraint == null) {
resetData();
notifyDataSetChangedInternal();
} else {
getFilter().filter(mConstraint);
}
}
private void notifyDataSetChangedInternal() {
super.notifyDataSetChanged();
}
/** Holds group title information for efficiency purposes. */
static class CommandExpandableMenuHeader {
TextView title;
}
/** Holds a {@link DragIcon} reference for efficiency purposes. */
static class CommandExpandableMenuItem {
TextView commandName, typeSigs;
}
private static class MenuDataHolder {
List<String> tags;
ListMultimap<String, String> tagCommandNames;
}
private void resetData() {
mTags = CommandHolder.getTags();
mTagCommandNames = CommandHolder.getTagCommandNames();
}
@Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
mConstraint = constraint;
FilterResults results = new FilterResults();
MenuDataHolder holder;
synchronized (mLock) {
holder = new MenuDataHolder();
}
if (constraint == null) {
holder.tags = CommandHolder.getTags();
holder.tagCommandNames = CommandHolder.getTagCommandNames();
results.values = holder;
} else {
String search = constraint.toString().toLowerCase(Locale.US);
List<String> newTags;
ListMultimap<String, String> newTagCmdNames;
synchronized (mLock) {
newTags = Lists.newArrayList();
newTagCmdNames = ArrayListMultimap.create();
}
for (final String tag : CommandHolder.getTags()) {
final String ltag = tag.toLowerCase(Locale.US);
if (ltag.contains(search)) {
newTags.add(tag);
newTagCmdNames.putAll(tag, CommandHolder.getCommandNamesFromTag(tag));
} else {
for (final String name : CommandHolder.getCommandNamesFromTag(tag)) {
final String lname = name.toLowerCase(Locale.US);
if (lname.contains(search)) {
newTagCmdNames.put(tag, name);
} else {
List<? extends CommandInfo> cmds = CommandHolder.getCommandsFromName(name);
cmdLoop: for (CommandInfo cmd : cmds) {
final String help = cmd.getHelp().toLowerCase(Locale.US);
if (help.contains(search)) {
newTagCmdNames.put(tag, name);
break cmdLoop;
}
final String cmdName = cmd.getName().toLowerCase(Locale.US);
if (cmdName.contains(search)) {
newTagCmdNames.put(tag, name);
break cmdLoop;
}
final List<String> tags = cmd.getTags();
for (final String innerTag : tags) {
final String linnerTag = innerTag.toLowerCase(Locale.US);
if (linnerTag.contains(search)) {
newTagCmdNames.put(tag, name);
break cmdLoop;
}
}
final List<String> argTys = cmd.getArgTypes();
for (final String argTy : argTys) {
final String largTy = argTy.toLowerCase(Locale.US);
if (largTy.contains(search)) {
newTagCmdNames.put(tag, name);
break cmdLoop;
}
}
final String resTy = cmd.getResultType().toLowerCase(Locale.US);
if (resTy.contains(search)) {
newTagCmdNames.put(tag, name);
break cmdLoop;
}
}
}
}
if (newTagCmdNames.containsKey(tag)) {
newTags.add(tag);
}
}
}
holder.tags = newTags;
holder.tagCommandNames = newTagCmdNames;
results.values = holder;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
MenuDataHolder holder = (MenuDataHolder) results.values;
mTags = holder.tags;
mTagCommandNames = holder.tagCommandNames;
notifyDataSetChangedInternal();
}
};
}
return mFilter;
}
}